/**
 * @File Name: tcp_communication.cpp
 * @brief  
 * @Author : LiWanglin email:lwl510ll@163.com
 * @Version : 1.0
 * @Creat Date : 2024-01-28
 * 
 * @copyright Copyright (c) 2024 LiWanglin
 */

#include "tcp_communication.h"
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

TcpCommunication::TcpCommunication()
{
    fd = -1;
    ip_addr = nullptr;
    port = -1;
}

TcpCommunication::~TcpCommunication()
{
    if(fd >  0) {
        close(fd);
        fd = -1;
    }

    if(nullptr != ip_addr) {
        free(ip_addr);
        ip_addr = nullptr;
    }
}

CMResult TcpCommunication::init()
{
    if (fd == -1) {
        fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if (fd <= 0) {
            return CM_CREAT_SOCKET_FAILED;
        }
    }

    /* 绑定套接字到一个地址 */
    if((ip_addr != NULL) && (port > 0)) {
        struct sockaddr_in server_addr;
        memset(&server_addr, 0, sizeof(server_addr));
        server_addr.sin_family = AF_INET;
        server_addr.sin_addr.s_addr = inet_addr(ip_addr);
        server_addr.sin_port = htons(port);
        if (bind(fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
            close(fd);
            fd = -1;
            return CM_BIND_SOCKET_FAILED;
        }
    } else {
        close(fd);
        fd = -1;
        return CM_BIND_SOCKET_FAILED;
    }

    // 监听连接请求
    if (listen(fd, 5) == -1) {
        close(fd);
        fd = -1;
        return CM_LISTEN_SOCKET_FAILED;
    }

    return CM_OK;
}

CMResult TcpCommunication::uninit()
{
    if(fd >  0) {
        close(fd);
        fd = -1;
    }

    if(nullptr != ip_addr) {
        free(ip_addr);
        ip_addr = nullptr;
    }

    return CM_OK;
}

CMResult TcpCommunication::set(int type, void *arg)
{
    switch (type) {
        case SET_SOCKET_ADDRESS:
        {
            if(arg) {
                ip_addr = (char *)malloc(strlen((char *)arg)+1);
                sprintf(ip_addr, "%s", (char *)arg);
            } else {
                return CM_NULL_POINT;
            }
            break;
        }


        case SET_SOCKET_PORT:
        {
            if(arg) {
                port = *(int *)arg;
            } else {
                return CM_NULL_POINT;
            }
            break;
        }

        default:
            break;
    }

    return CM_OK;
}


CMResult TcpCommunication::get(int type, void *arg)
{
    return CM_OK;
}